package com.onlyxiahui.of.muc.service;

import java.io.StringReader;
import java.text.ParseException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.Date;
import java.util.List;
import java.util.ListIterator;
import java.util.Map;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;
import org.jivesoftware.openfire.PacketRouter;
import org.jivesoftware.openfire.XMPPServer;
import org.jivesoftware.openfire.muc.MUCRoom;
import org.jivesoftware.openfire.muc.MUCRoomHistory;
import org.jivesoftware.openfire.muc.MultiUserChatService;
import org.jivesoftware.util.StringUtils;
import org.jivesoftware.util.XMPPDateTimeFormat;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.xmpp.packet.JID;
import org.xmpp.packet.Message;

import com.onlyxiahui.of.muc.bean.RoomInfo;
import com.onlyxiahui.of.muc.dao.RoomChatDAO;
import com.onlyxiahui.of.muc.dao.RoomDAO;
import com.onlyxiahui.of.muc.dao.UserDAO;

/**
 * @author XiaHui
 * @date 2017-12-06 09:36:45
 */
public class RoomOfflineMessageService {
	private static final Logger log = LoggerFactory.getLogger(RoomOfflineMessageService.class);

	// private static final RoomOfflineMessageService roms = new
	// RoomOfflineMessageService();
	//
	// public static RoomOfflineMessageService getInstance() {
	// return roms;
	// }

	private static final ExecutorService pool = Executors.newFixedThreadPool(1);
	private static final ConcurrentLinkedQueue<Message> messageQueue = new ConcurrentLinkedQueue<Message>();// 任务队列
	private static final SAXReader xmlReader = new SAXReader();

	static {
		pool.execute(new MessageThread());
		xmlReader.setEncoding("UTF-8");
	}

	public RoomOfflineMessageService() {

	}

	private static final XMPPDateTimeFormat xmppDateTime = new XMPPDateTimeFormat();

	public void handlerRoomOfflineMessage01(JID jid) {
		String userJid = jid.toBareJID();
		MultiUserChatService service = XMPPServer.getInstance().getMultiUserChatManager()
				.getMultiUserChatService("conference");
		long offlineTime = UserDAO.getOfflineTime(userJid);

		Date offlineDate = null;
		if (offlineTime > 0) {
			offlineDate = new Date(offlineTime);
		} else {
			return;
		}
		List<Map<String, String>> list = RoomDAO.getMUCInfo(userJid);
		if (list != null && !list.isEmpty()) {
			for (Map<String, String> map : list) {
				String roomName = map.get("name");
				MUCRoom mucroom = service.getChatRoom(roomName);
				List<Message> sendList = new ArrayList<Message>();

				if (null != mucroom) {
					MUCRoomHistory history = mucroom.getRoomHistory();

					ListIterator<Message> iterator = history.getReverseMessageHistory();
					Element delayInformation = null;
					while (iterator.hasPrevious()) {
						Message message = iterator.previous();

						delayInformation = message.getChildElement("delay", "urn:xmpp:delay");

						if (null != delayInformation) {
							try {
								String stamp = delayInformation.attributeValue("stamp");
								if (null != stamp) {

									Date delayedDate = xmppDateTime.parseString(stamp);
									if (delayedDate != null && delayedDate.after(offlineDate)) {
										sendList.add(0, message);
									}
								}
							} catch (ParseException e) {
								e.printStackTrace();
							}
						}
					}
				}

				Collections.sort(sendList, new Comparator<Message>() {

					@Override
					public int compare(Message o1, Message o2) {
						String stamp1 = o1.getChildElement("delay", "urn:xmpp:delay").attributeValue("stamp");
						String stamp2 = o2.getChildElement("delay", "urn:xmpp:delay").attributeValue("stamp");
						int i = 0;

						try {
							Date delayedDate1 = xmppDateTime.parseString(stamp1);
							Date delayedDate2 = xmppDateTime.parseString(stamp2);
							boolean after = delayedDate1.after(delayedDate2);
							i = (after ? 1 : -1);
						} catch (ParseException e) {
							e.printStackTrace();
						}
						return i;
					}
				});

				for (Message message : sendList) {
					message.setTo(jid);
					put(message);
				}
			}
		}
	}

	public void handlerRoomOfflineMessage(JID jid) {
		String userJid = jid.toBareJID();
		String offlineTime = UserDAO.getOfflineTimeString(userJid);
		List<RoomInfo> roomList = RoomDAO.getRoomInfoList(userJid);
		if (null != roomList && !roomList.isEmpty() && null != offlineTime && !offlineTime.isEmpty()) {
			sendMessage(jid, roomList, offlineTime);
		}
	}

	private void sendMessage(JID toJid, List<RoomInfo> roomList, String offlineTime) {
		long otime = Long.parseLong(offlineTime) - (1000L * 60L * 60L);
		offlineTime = StringUtils.zeroPadString(Long.toString(otime), 15);
		for (RoomInfo room : roomList) {
			long roomId = room.getRoomId();

			List<Map<String, String>> messageList = RoomChatDAO.getRoomOfflineMessageList(roomId, offlineTime);
			if (null != messageList && !messageList.isEmpty()) {
				for (Map<String, String> map : messageList) {
					String stanza = map.get("stanza");
					String logTime = map.get("logTime");
					Date sentDate = null;
					if (null != logTime && !logTime.isEmpty()) {
						long time = Long.parseLong(logTime.trim());
						sentDate = new Date(time);
					}

					if (null != stanza && !stanza.isEmpty()) {
						try {
							Element element = xmlReader.read(new StringReader(stanza)).getRootElement();
							Message message = new Message(element);
							if (null != sentDate) {
								Element delayInformation = message.addChildElement("delay", "urn:xmpp:delay");
								delayInformation.addAttribute("stamp", XMPPDateTimeFormat.format(sentDate));
							}
							message.setTo(toJid);
							put(message);
						} catch (DocumentException e) {
							// e.printStackTrace();
							log.error("", e);
						}
					}
				}
			}

		}
	}

	public void put(Message message) {
		messageQueue.add(message);
	}

	static class MessageThread extends Thread {

		PacketRouter router = XMPPServer.getInstance().getPacketRouter();

		public void run() {
			while (true) {
				handleMesage();// 处理任务
				threadSleep(200);
			}
		}

		private void handleMesage() {
			Message message;
			while (messageQueue.peek() != null) {
				message = messageQueue.poll();
				try {
					router.route(message);
				} catch (Exception e) {
					log.error("", e);
				}
			}
		}

		private void threadSleep(long time) {
			try {
				sleep(time);
			} catch (InterruptedException e) {
				log.error("", e);
			}
		}
	}
}
